/**
 * 验证密码强度
 * @param {string} password 密码
 */
function valiPasswordStrong(password) {
  var strong = 0,
    character = 0,
    fromCharacterSets = []
  var match = function (match, length) {
    return { match, length }
  }
  var matches = {
    'ASCII Lowercase': match(/[a-z]/, 26),
    'ASCII Uppercase': match(/[A-Z]/, 26),
    'ASCII Numbers': match(/\d/, 10),
    'ASCII Top Row Symbols': match(/[!@£#\$%\^&\*\(\)\-_=\+]/, 15),
    'ASCII Other Symbols': match(/[\?\/\.>\,<`~\\|"';:\]\}\[\{\s]/, 19),
    'Unicode Latin 1 Supplement': match(/[\u00A1-\u00FF]/, 94),
    'Unicode Latin Extended A': match(/[\u0100-\u017F]/, 128),
    'Unicode Latin Extended B': match(/[\u0180-\u024F]/, 208),
    'Unicode Latin Extended C': match(/[\u2C60-\u2C7F]/, 32),
    'Unicode Latin Extended D': match(/[\uA720-\uA7FF]/, 29),
    'Unicode Cyrillic Uppercase': match(/[\u0410-\u042F]/, 32),
    'Unicode Cyrillic Lowercase': match(/[\u0430-\u044F]/, 32)
  }
  for (var i in matches) {
    if (password.match(matches[i].match)) {
      character += matches[i].length
      fromCharacterSets.push(i)
    }
  }
  strong = Math.log10(Math.pow(character, password.length))
  return { fromCharacterSets, strong }
}

/**
 * 笛卡尔数据积
 * @param {Array} listLv2  二维数组
 * @return {Array} 笛卡尔积
 */
function specCartesian(listLv2) {
  const merger = (a, b) => {
    const result = []
    for (const aItem of a) {
      for (const bItem of b) {
        if (Array.isArray(aItem)) {
          result.push([...aItem, bItem])
        } else {
          result.push([aItem, bItem])
        }
      }
    }
    return result
  }
  return listLv2.reduce((p, c) => (p ? merger(p, c) : c))
}

/**
 * 对象深拷贝【中级版】不含边界情况，高级版参见lodash's _.cloneDeep()
 * @param {Object} source
 * @returns {Object}
 */
function deepCloneObj(source) {
  if (!source && typeof source !== 'object') {
    return null
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepCloneObj(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * 阿拉伯数字转中文数字
 * @param {(number|string)} num 阿拉伯数字
 * @returns {string}
 */
function toChinesNum(num) {
  num = parseFloat(num)
  const chnNumChar = [
    '零',
    '一',
    '二',
    '三',
    '四',
    '五',
    '六',
    '七',
    '八',
    '九'
  ]
  const chnUnitSection = ['', '万', '亿', '万亿', '亿亿']
  const chnUnitChar = ['', '十', '百', '千']
  const SectionToChinese = function (section) {
    var strIns = '',
      chnStr = ''
    var unitPos = 0
    var zero = true
    while (section > 0) {
      var v = section % 10
      if (v === 0) {
        if (!zero) {
          zero = true
          chnStr = chnNumChar[v] + chnStr
        }
      } else {
        zero = false
        strIns = chnNumChar[v]
        strIns += chnUnitChar[unitPos]
        chnStr = strIns + chnStr
      }
      unitPos++
      section = Math.floor(section / 10)
    }
    return chnStr
  }
  var unitPos = 0
  var strIns = '',
    chnStr = ''
  var needZero = false
  if (num === 0) {
    return chnNumChar[0]
  }
  while (num > 0) {
    var section = num % 10000
    if (needZero) {
      chnStr = chnNumChar[0] + chnStr
    }
    strIns = SectionToChinese(section)
    strIns += section !== 0 ? chnUnitSection[unitPos] : chnUnitSection[0]
    chnStr = strIns + chnStr
    needZero = section < 1000 && section > 0
    num = Math.floor(num / 10000)
    unitPos++
  }
  chnStr = chnStr.replace(/一十/g, '十')
  return chnStr
}

module.exports = {
  valiPasswordStrong,
  specCartesian,
  deepCloneObj,
  toChinesNum
}
